#include "drv_pin.h"
#include "hc32_ddl.h"
#include "hc32f460_exint_nmi_swi.h"
#include <stdio.h>

static void Exirq_Handle_Pin00(void);
static void Exirq_Handle_Pin01(void);
static void Exirq_Handle_Pin02(void);
static void Exirq_Handle_Pin03(void);
static void Exirq_Handle_Pin04(void);
static void Exirq_Handle_Pin05(void);
static void Exirq_Handle_Pin06(void);
static void Exirq_Handle_Pin07(void);
static void Exirq_Handle_Pin08(void);
static void Exirq_Handle_Pin09(void);
static void Exirq_Handle_Pin10(void);
static void Exirq_Handle_Pin11(void);
static void Exirq_Handle_Pin12(void);
static void Exirq_Handle_Pin13(void);
static void Exirq_Handle_Pin14(void);
static void Exirq_Handle_Pin15(void);

struct hc32_pin_irq_map{
    uint16_t pinbit;
    uint16_t irqno;
};

static const struct hc32_pin_irq_map pin_irq_map[] = {
	{Pin00, INT_PORT_EIRQ0},{Pin01, INT_PORT_EIRQ1},
    {Pin02, INT_PORT_EIRQ2},{Pin03, INT_PORT_EIRQ3},
    {Pin04, INT_PORT_EIRQ4},{Pin05, INT_PORT_EIRQ5},
    {Pin06, INT_PORT_EIRQ6},{Pin07, INT_PORT_EIRQ7},
    {Pin08, INT_PORT_EIRQ8},{Pin09, INT_PORT_EIRQ9},
    {Pin10, INT_PORT_EIRQ10},{Pin11, INT_PORT_EIRQ11},
    {Pin12, INT_PORT_EIRQ12},{Pin13, INT_PORT_EIRQ13},
    {Pin14, INT_PORT_EIRQ14},{Pin15, INT_PORT_EIRQ15},
};

struct hc32_pin_irq_hdr{
    uint16_t        pin;
    uint16_t       mode;
    void (*hdr)(void);
	void (*callback)(void);
};

static struct hc32_pin_irq_hdr pin_irq_hdr_tab[] = {
    {-1, 0, NULL,Exirq_Handle_Pin00},{-1, 0, NULL,Exirq_Handle_Pin01},
    {-1, 0, NULL,Exirq_Handle_Pin02},{-1, 0, NULL,Exirq_Handle_Pin03},
	{-1, 0, NULL,Exirq_Handle_Pin04},{-1, 0, NULL,Exirq_Handle_Pin05},
    {-1, 0, NULL,Exirq_Handle_Pin06},{-1, 0, NULL,Exirq_Handle_Pin07},
    {-1, 0, NULL,Exirq_Handle_Pin08},{-1, 0, NULL,Exirq_Handle_Pin09},
    {-1, 0, NULL,Exirq_Handle_Pin10},{-1, 0, NULL,Exirq_Handle_Pin11},
    {-1, 0, NULL,Exirq_Handle_Pin12},{-1, 0, NULL,Exirq_Handle_Pin13},
    {-1, 0, NULL,Exirq_Handle_Pin14},{-1, 0, NULL,Exirq_Handle_Pin15},
};

void hc32_pin_mode(uint32_t pin,uint32_t mode){
	if(pin == 0){
		return;
	}
	stc_port_pcr_field_t *PCRx;
    stc_port_pfsr_field_t * PFSRx;
	stc_port_init_t pstcPortInit;
	PORT_Unlock();
	PCRx = (stc_port_pcr_field_t *)((uint32_t)(&M4_PORT->PCRA0) + pin);
    PFSRx = (stc_port_pfsr_field_t *)((uint32_t)(&M4_PORT->PFSRA0) + pin);
	
	pstcPortInit.enExInt = Disable;
	pstcPortInit.enPullUp = Disable;
	pstcPortInit.enPinMode = Pin_Mode_Out;
	switch(mode){
		case PIN_MODE_OUTPUT:{
			pstcPortInit.enPinMode = Pin_Mode_Out;
			pstcPortInit.enExInt = Disable;
			pstcPortInit.enPullUp = Disable;
		}break;
		case PIN_MODE_OUTPUT_PULLUP:{
			pstcPortInit.enPinMode = Pin_Mode_Out;
			pstcPortInit.enExInt = Disable;
			pstcPortInit.enPullUp = Enable;
		}break;
		case PIN_MODE_INPUT:{
			pstcPortInit.enPinMode = Pin_Mode_In;
			pstcPortInit.enExInt = Disable;
			pstcPortInit.enPullUp = Disable;
		}break;
		case PIN_MODE_INPUT_PULLUP:{
			pstcPortInit.enPinMode = Pin_Mode_In;
			pstcPortInit.enExInt = Disable;
			pstcPortInit.enPullUp = Enable;
		}break;
		case PIN_MODE_INPUT_PULLDOWN:{
			pstcPortInit.enPinMode = Pin_Mode_In;
			pstcPortInit.enExInt = Disable;
			pstcPortInit.enPullUp = Disable;
		}break;
		case PIN_MODE_OUTPUT_OD:{
			pstcPortInit.enPinMode = Pin_Mode_Out;
			pstcPortInit.enExInt = Disable;
			pstcPortInit.enPullUp = Disable;
		}break;
	}
	
	PCRx->LTE = pstcPortInit.enLatch;
	PCRx->INTE = pstcPortInit.enExInt;
	PCRx->INVE = pstcPortInit.enInvert;
	PCRx->PUU = pstcPortInit.enPullUp;
	PCRx->NOD = pstcPortInit.enPinOType;
	PCRx->DRV = pstcPortInit.enPinDrv;
	switch (pstcPortInit.enPinMode){
		case Pin_Mode_In:
			PCRx->DDIS  = 0u;
			PCRx->POUTE = 0u;
		break;
		case Pin_Mode_Out:
			PCRx->DDIS  = 0u;
			PCRx->POUTE = 1u;
		break;
		case Pin_Mode_Ana:
			PCRx->DDIS  = 1u;
		break;
		default:
		break;
	}
	
	PFSRx->BFE = pstcPortInit.enPinSubFunc;
	PORT_Lock();
}

void hc32_pin_write(uint32_t pin,uint32_t value){
	uint16_t port = (pin/0x40)%0x10;
	uint16_t pin_t = (pin - port*0x40)/0x04;
	uint16_t *POSRx;
	if(value == PIN_HIGH){
		POSRx = (uint16_t *)((uint32_t)(&M4_PORT->POSRA) + 0x10u * port);
	}
	if(value == PIN_LOW){
		POSRx = (uint16_t *)((uint32_t)(&M4_PORT->PORRA) + 0x10u * port);
	}
    *POSRx |= (1u <<pin_t);
}

uint8_t hc32_pin_read(uint32_t pin){
	en_flag_status_t value = 0;
	uint16_t port = (pin/0x40)%0x10;
	uint16_t pin_t = (pin - port*0x40)/0x04;
	uint32_t *PIDRx = (uint32_t *)((uint32_t)(&M4_PORT->PIDRA) + 0x10u * port);
	value = (en_flag_status_t)(!!(*PIDRx & (1u <<pin_t)));
    return value;
}

void hc32_pin_attach_irq(uint32_t pin, uint32_t mode,void (*hdr)(void)){
	stc_exint_config_t stcExtiConfig;
	stc_irq_regi_conf_t stcIrqRegiConf;
	MEM_ZERO_STRUCT(stcExtiConfig);
	MEM_ZERO_STRUCT(stcIrqRegiConf);

	uint16_t port = (pin/0x40)%0x10;
	uint16_t pin_t = (pin - port*0x40)/0x04;
	stcExtiConfig.enExitCh = 1u*pin_t;
	stcExtiConfig.enFilterEn = Enable;
	stcExtiConfig.enFltClk = Pclk3Div8;
	switch(mode){
		case PIN_IRQ_MODE_RISING:{
			stcExtiConfig.enExtiLvl = ExIntRisingEdge;   //
		}break;
		case PIN_IRQ_MODE_FALLING:{
			stcExtiConfig.enExtiLvl = ExIntFallingEdge;   //
		}break;
		case PIN_IRQ_MODE_RISING_FALLING:{
			stcExtiConfig.enExtiLvl = ExIntBothEdge;   //
		}break;
		case PIN_IRQ_MODE_HIGH_LEVEL:{
			stcExtiConfig.enExtiLvl = ExIntLowLevel;   //
		}break;
		case PIN_IRQ_MODE_LOW_LEVEL:{
			stcExtiConfig.enExtiLvl = ExIntLowLevel;   //
		}break;
	}
	EXINT_Init(&stcExtiConfig);
	stcIrqRegiConf.enIntSrc = 1u*pin_t;
	stcIrqRegiConf.enIRQn = 16 + pin_t;
	pin_irq_hdr_tab[pin_t].hdr = hdr;
	pin_irq_hdr_tab[pin_t].pin = 1u*pin_t;
	stcIrqRegiConf.pfnCallback = pin_irq_hdr_tab[pin_t].callback;
	enIrqRegistration(&stcIrqRegiConf);
	NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
	NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
	NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
}

void hc32_pin_irq_enable(uint32_t pin, uint32_t enabled){
	uint16_t port = (pin/0x40)%0x10;
	uint16_t pin_t = (pin - port*0x40)/0x04;
	en_int_wkup_src_t wakeSrc = (1u << pin_t); 
	PORT_Unlock();
	stc_port_pcr_field_t *PCRx = (stc_port_pcr_field_t *)((uint32_t)(&M4_PORT->PCRA0) + pin);
	if(enabled == PIN_IRQ_ENABLE){
		PCRx->INTE = Enable;
	}
	if(enabled == PIN_IRQ_DISABLE){
		PCRx->INTE = Disable;
	}
	PORT_Lock();
	enabled == 1 ? enIntWakeupEnable(wakeSrc):enIntWakeupDisable(wakeSrc);
}

static void Exirq_Handle_Pin00(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[0].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[0].pin);
		pin_irq_hdr_tab[0].hdr();
	}
}

static void Exirq_Handle_Pin01(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[1].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[1].pin);
		pin_irq_hdr_tab[1].hdr();
	}
}

static void Exirq_Handle_Pin02(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[2].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[2].pin);
		pin_irq_hdr_tab[2].hdr();
	}
}
static void Exirq_Handle_Pin03(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[3].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[3].pin);
		pin_irq_hdr_tab[3].hdr();
	}
}
static void Exirq_Handle_Pin04(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[4].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[4].pin);
		pin_irq_hdr_tab[4].hdr();
	}
}
static void Exirq_Handle_Pin05(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[5].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[5].pin);
		pin_irq_hdr_tab[5].hdr();
	}
}
static void Exirq_Handle_Pin06(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[6].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[6].pin);
		pin_irq_hdr_tab[6].hdr();
	}
}
static void Exirq_Handle_Pin07(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[7].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[7].pin);
		pin_irq_hdr_tab[7].hdr();
	}
}
static void Exirq_Handle_Pin08(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[8].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[8].pin);
		pin_irq_hdr_tab[8].hdr();
	}
}
static void Exirq_Handle_Pin09(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[9].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[9].pin);
		pin_irq_hdr_tab[9].hdr();
	}
}
static void Exirq_Handle_Pin10(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[10].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[10].pin);
		pin_irq_hdr_tab[10].hdr();
	}
}
static void Exirq_Handle_Pin11(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[11].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[11].pin);
		pin_irq_hdr_tab[11].hdr();
	}
}
static void Exirq_Handle_Pin12(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[12].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[12].pin);
		pin_irq_hdr_tab[12].hdr();
	}
}
static void Exirq_Handle_Pin13(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[13].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[13].pin);
		pin_irq_hdr_tab[13].hdr();
	}
}
static void Exirq_Handle_Pin14(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[14].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[14].pin);
		pin_irq_hdr_tab[14].hdr();
	}
}
static void Exirq_Handle_Pin15(void){
	if(Set == EXINT_IrqFlgGet(pin_irq_hdr_tab[15].pin)){
		EXINT_IrqFlgClr(pin_irq_hdr_tab[15].pin);
		pin_irq_hdr_tab[15].hdr();
	}
}
